﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Spring.Aspects.Logging;
using AopAlliance.Intercept;
using Common.Logging;

namespace Library.Spring.Logging
{
    public class LoggingAdvice : SimpleLoggingAdvice
    {
        private LogLevel errorLogLevel = LogLevel.Error;
        public LogLevel ErrorLogLevel 
        {
            get
            {
                return errorLogLevel;
            }
            set
            {
                this.errorLogLevel = value;
            }
        }

        protected override object InvokeUnderLog(IMethodInvocation invocation, ILog log)
        {
            object returnValue = null;
            bool exitThroughException = false;

            DateTime startTime = DateTime.Now;
            string uniqueIdentifier = null;

            if (LogUniqueIdentifier)
            {
                uniqueIdentifier = CreateUniqueIdentifier();
            }
            try
            {
                WriteToLog(LogLevel, log, GetEntryMessage(invocation, uniqueIdentifier), null);
                returnValue = invocation.Proceed();
                return returnValue;
            }
            catch (Exception e)
            {
                TimeSpan executionTimeSpan = DateTime.Now - startTime;
                WriteToLog(errorLogLevel, log, GetExceptionMessage(invocation, e, executionTimeSpan, uniqueIdentifier), e);
                exitThroughException = true;
                throw;
            }
            finally
            {
                if (!exitThroughException)
                {
                    TimeSpan executionTimeSpan = DateTime.Now - startTime;
                    WriteToLog(LogLevel, log, GetExitMessage(invocation, returnValue, executionTimeSpan, uniqueIdentifier), null);
                }
            }
        }

        private void WriteToLog(LogLevel logLevel, ILog log, string text, Exception e)
        {
            switch (logLevel)
            {
                case LogLevel.All:
                case LogLevel.Trace:
                    if (!log.IsTraceEnabled)
                    {
                        break;
                    }
                    if (e != null)
                    {
                        log.Trace(text, e);
                        return;
                    }
                    log.Trace(text);
                    return;

                case LogLevel.Debug:
                    if (!log.IsDebugEnabled)
                    {
                        break;
                    }
                    if (e != null)
                    {
                        log.Debug(text, e);
                        return;
                    }
                    log.Debug(text);
                    return;

                case LogLevel.Info:
                    if (!log.IsInfoEnabled)
                    {
                        break;
                    }
                    if (e != null)
                    {
                        log.Info(text, e);
                        return;
                    }
                    log.Info(text);
                    return;

                case LogLevel.Warn:
                    if (!log.IsWarnEnabled)
                    {
                        break;
                    }
                    if (e != null)
                    {
                        log.Warn(text, e);
                        break;
                    }
                    log.Warn(text);
                    return;

                case LogLevel.Error:
                    if (!log.IsErrorEnabled)
                    {
                        break;
                    }
                    if (e != null)
                    {
                        log.Error(text, e);
                        return;
                    }
                    log.Error(text);
                    return;

                case LogLevel.Fatal:
                    if (!log.IsFatalEnabled)
                    {
                        break;
                    }
                    if (e != null)
                    {
                        log.Fatal(text, e);
                        return;
                    }
                    log.Fatal(text);
                    return;

                case LogLevel.Off:
                    break;

                default:
                    return;
            }
        }
    }
}
